#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include "parse.h"

void execute(char **tar);
void runCommand(char *tar);
void fullExecute(char **orig, int start, int end);
void fullExecuteHelper(char **tar);
void redirect(char **orig, int cur);
void execute2(char **orig, int cur);
void assessLeft(char **orig, int cur);
void assessRight(char **orig, int cur);

void runCommand(char *tar){
    char *argumentArray[255];
    interpret(tar, argumentArray);
    fullExecuteHelper(argumentArray);
}

void fullExecuteHelper(char **tar) {
  int end;
  end = 0;
  while(tar[end]) //seek to the end of the array
    end++;
  fullExecute(tar, 0, end);
}

void fullExecute(char **orig, int start, int end) {//full recursive execute command
  int cur, length;
  cur = end - 1;
  if (cur < 0) 
    return;
  while(strcmp(";",orig[cur]) && !(cur==start))
    cur--;
  char** tar = orig;
  tar[end] = 0; //truncate end
  if(cur == start) //base case
    execute2(tar, cur);
  else {
    fullExecute(tar,0,cur);
    execute2(tar, cur + 1);
  }
}

void execute2(char **orig, int cur){
  int childPiD, waitStatus;
  childPiD = fork(); 
  if (childPiD == 0) 
    redirect(orig, cur);
  else
    wait(&waitStatus);
}

void redirect(char **orig, int cur) {  
  char **tar = orig;
  int i, fd, fd2;
  for(i = 0; i < cur; i++) 
    tar++;
  cur = 0;
  while(tar[cur]) 
    cur++;
  cur--;
  while(strcmp(">",tar[cur]) && strcmp("<",tar[cur]) && strcmp("2>",tar[cur]) && strcmp(">>",tar[cur]) && strcmp("|",tar[cur]) && cur)
    cur--; 
  if(!cur)
    execute(tar);
  else if(!strcmp("|",tar[cur])) {
    int childPiD, waitStatus;
    childPiD = fork(); 
    if (childPiD == 0) {
      fd = open("t.txt", O_RDWR | O_CREAT, 0666);
      if (fd == -1) {
	printf("fd: %d, errno: %d, error %s\n", fd, errno, strerror(errno));
	return;
      }
      fd2 = dup(STDOUT_FILENO);
      dup2(fd, STDOUT_FILENO);
      close(fd); 
      assessLeft(tar, cur);
      dup2(fd2, STDOUT_FILENO);
    }
    else {
      wait(&waitStatus);
      fd = open("t.txt", O_RDONLY);
      if (fd == -1) {
	printf("fd: %d, errno: %d, error %s\n", fd, errno, strerror(errno));
	return;
      }
      fd2 = dup(STDIN_FILENO);
      dup2(fd, STDIN_FILENO);
      close(fd);
      assessRight(tar, cur + 1);
      dup2(fd2,STDIN_FILENO);
    }
    /*
    childPiD = fork();
    if(childPiD == 0) 
      execl("/bin/rm", "rm", "t.txt", NULL);
    else
      wait(&waitStatus);
    */
    return;
  }    
  else {
    umask(0000);
    int fd, fd2;
    if(!strcmp(">>",tar[cur])) {
      fd = open(tar[cur + 1], O_WRONLY | O_APPEND | O_CREAT, 0644);
      if (fd == -1) {
        printf("fd: %d, errno: %d, error %s\n", fd, errno, strerror(errno));
        return;
      }
      fd2 = dup(STDOUT_FILENO);
      dup2(fd, STDOUT_FILENO);
      assessLeft(tar, cur);
      dup2(fd2, STDOUT_FILENO);
      assessRight(tar, cur + 1);
      close(fd);
      return;
    }
    else if(!strcmp("2>",tar[cur])) {
      fd = open(tar[cur + 1], O_WRONLY | O_APPEND | O_CREAT | O_TRUNC, 0644);
      if (fd == -1) {
	printf("fd: %d, errno: %d, error %s\n", fd, errno, strerror(errno));
	return;
      }
      fd2 = dup(STDERR_FILENO);
      dup2(fd, STDERR_FILENO);
      assessLeft(tar, cur);
      dup2(fd2, STDERR_FILENO);
      assessRight(tar, cur + 1);
      close(fd);
      return;
    }
    else if(!strcmp("<",tar[cur])) {
      fd = open(tar[cur + 1], O_RDONLY);
      if (fd == -1) {
	printf("fd: %d, errno: %d, error %s\n", fd, errno, strerror(errno));
	return;
      }
      fd2 = dup(STDIN_FILENO);
      dup2(fd, STDIN_FILENO);
      close(fd);
      assessLeft(tar, cur);
      dup2(fd2,STDIN_FILENO);
      assessRight(tar, cur + 1);
      return;
    }
    else if(!strcmp(">",tar[cur])) {
      fd = open(tar[cur + 1], O_WRONLY | O_APPEND | O_CREAT | O_TRUNC, 0644);
      if (fd == -1) {
	printf("fd: %d, errno: %d, error %s\n", fd, errno, strerror(errno));
	return;
      }
      fd2 = dup(STDOUT_FILENO);
      dup2(fd, STDOUT_FILENO);
      assessLeft(tar, cur);
      dup2(fd2, STDOUT_FILENO);
      assessRight(tar, cur + 1);
      close(fd);
      return;
    }
  }
}

void assessLeft(char **orig, int cur) {
  char **tar = orig;
  tar[cur] = 0;
  redirect(tar, 0);
}

void assessRight(char **orig, int cur) {
  char **tar = orig;
  int i;
  for(i = 0; i < cur; i++) 
    tar++;
  execute(tar);
}

void execute(char **tar){//basic execute command
  if(strcmp(tar[0],"cd")== 0) {
    chdir(tar[1]);
    return;
  }
  char temp[255] = "/bin/";
  char temp2[255] = "/usr/bin/";
  strncat(temp, tar[0], 250);
  strncat(temp2, tar[0], 250);
  if(!(execv(tar[0], tar) == -1))
    return;
  else if(!(execv(temp,tar) == -1))
    return;
  else if(!(execv(temp2,tar) == -1))
    return;
  else {
    puts("Invalid Command.\n");
    return;
   }
  execv(temp, tar);
}
